<?php

declare(strict_types=1);

namespace App\Robot\Service;

use App\CustHub\Mapper\ChServerMapper;
use App\Robot\Dto\EmojiMsgDTO;
use App\Robot\Dto\FileMessageDTO;
use App\Robot\Dto\ImageMessageDTO;
use App\Robot\Dto\MiniProgramMessageDTO;
use App\Robot\Dto\QuoteMsgDTO;
use App\Robot\Dto\UrlMessageDTO;
use App\Robot\Dto\VideoChannelMessageDTO;
use App\Robot\Dto\VideoMessageDTO;
use GuzzleHttp\Client;
use Hyperf\Codec\Packer\JsonPacker;
use Hyperf\Contract\PackerInterface;
use Hyperf\Coroutine\Coroutine;
use Hyperf\Guzzle\CoroutineHandler;
use Mine\Exception\NormalStatusException;
use function Hyperf\Collection\collect;

class RobotApiService
{
    protected Client $client;

    protected PackerInterface $packer;

    protected string $key;

    private bool $throw = false;

    private mixed $errorMsg = '';

    protected mixed $serverId;

    public function __construct(mixed $serverId,String $key = '')
    {
        $handler = null;
        if (Coroutine::inCoroutine()) {
            $handler = new CoroutineHandler();
        }

        if(\Hyperf\Support\env('IS_LOCAL')){
            $serverId = 1;
        }

        $this->serverId = $serverId;
        $baseUri = container()->get(ChServerMapper::class)->getUriById($serverId);

        $this->key = $key;
        $this->client = new Client([
            'base_uri' => $baseUri,
            'timeout' => 30,
            'handler' => $handler,
        ]);
        $this->packer = new JsonPacker();
    }

    public function setKey(string $key): RobotApiService
    {
        $this->key = $key;
        return $this;
    }

    public function setThrow(bool $throw): RobotApiService
    {
        $this->throw = $throw;
        return $this;
    }

    /**
     * 获取登录二维码
     * @return array
     */
    public function getLoginQrCode(string $customerParam = '',string $uuid = ''): mixed
    {
        $data = $this->post('/login/getLoginQrCode', [
            'key' => $this->key,
            'customerParam' => $customerParam,
            'uuid' => $uuid,
        ]);
        return $data;
    }

    /**
     * 登录验证
     * @param string $loginQrcodeKey
     * @param string $verifyCode
     * @return array
     */
    public function verifyLogin(string $loginQrcodeKey,string $verifyCode): mixed
    {
        stdout_log()->info("机器人人登录验证中...".$loginQrcodeKey);
        $data = $this->post('/login/verifyLogin', [
            'key' => $this->key,
            'loginQrcodeKey' => $loginQrcodeKey,
            'verifyCode' => $verifyCode
        ]);
        return $data;
    }

    public function getLoginStatus(): mixed
    {
        $data = $this->post('/login/getStatus', [
            'key' => $this->key,
        ]);
        return $data;
    }

    /**
     * 自动登录
     * @param string $userId
     * @param mixed $customerParam 自定义参数
     * @return mixed
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function autoLogin(string $userId,mixed $customerParam,string $uuid): mixed
    {
        $data = $this->post('/login/autoLogin', [
            'key' => $this->key,
            'userId' => $userId,
            'customerParam' => $customerParam.'_'.$this->serverId,
            'uuid' => $uuid
        ]);
        return $data;
    }

    /**
     * 注销登录
     * @return array
     */
    public function loginOut(): mixed
    {
        $data = $this->post('/login/loginOut', [
            'key' => $this->key,
        ]);
        return $data;
    }

    public function resetClient():mixed
    {
        $data = $this->post('/login/resetClient', [
            'key' => $this->key,
        ]);
        return $data;
    }

    /**
     * 获取会话列表详情
     * @param int $getFlag
     * @return array
     */
    public function getChatListDetail(int $getFlag): mixed
    {
        $data = $this->post('/common/getChatListDetail', [
            'key' => $this->key,
            'getFlag' => $getFlag
        ]);
        return $data;
    }

    /**
     * 设置外部联系人标签
     * @param string $userId
     * @param array $labelList
     * @return mixed
     */
    public function editLabel(string $userId,array $labelList): mixed
    {
        $data = $this->post('/contact/editLabel', [
            'key' => $this->key,
            'userId' => $userId,
            'labelList' => $labelList
        ]);
        return $data;
    }

    /**
     * 修改备注
     * @param string $userId
     * @param string $remark
     * @return array
     */
    public function editRemarkMobile(string $userId,string $remark,string $desc,string $companyRemark,array $mobileList,array $labelList): mixed
    {
        $data = $this->post('/contact/editRemarkMobile', [
            'key' => $this->key,
            'userId' => $userId,
            'desc' => $desc,
            'remark' => $remark,
            'companyRemark' => $companyRemark,
            'mobileList' => $mobileList,
            'labelList' => $labelList
        ]);
        return $data;
    }

    /**
     * @param mixed $roomWxId
     * @param int $setType 1: 置顶
     * 2: 取消置顶
     * 3: 开启免打扰
     * 4: 取消免打扰
     * 5: 保存群聊到通讯录
     * 6: 从通讯录移除群聊
     * @return array
     */
    public function settingChat(mixed $roomWxId, int $setType): mixed
    {
        $data = $this->post('/message/settingChat', [
            'key' => $this->key,
            'chatId' => $roomWxId,
            'setType' => $setType
        ]);
        return $data;
    }

    /**
     * 获取内部联系人列表
     * @param string $currentVersion
     * @return array|false|mixed
     */
    public function getEmployeeList(string $currentVersion = '')
    {
        $data = $this->post('/employee/list', [
            'key' => $this->key,
            'current_version' => $currentVersion
        ]);
        return $data;
    }

    /**
     * 获取员工详情
     * @param array $contactList
     * @return array
     */
    public function getEmployeeDetail(array $contactList): mixed
    {
        $data = $this->post('/employee/detail', [
            'key' => $this->key,
            'contactList' => $contactList
        ]);
        return $data;
    }

    /**
     * 根据手机号搜索联系人
     * @param string $mobile
     * @return array|false|mixed
     */
    public function searchContacts(string $mobile): mixed
    {
        $data = $this->post('/friend/searchContacts', [
            'key' => $this->key,
            'keyword' => $mobile
        ]);
        return $data;
    }

    /**
     * 添加外部联系人
     * @param mixed $unionId
     * @param mixed $userId
     * @param string $verifyText 验证文本
     * @return array|false|mixed
     */
    public function addSearchContacts(mixed $unionId,mixed $userId,string $verifyText = ''): mixed
    {
        $data = $this->post('/friend/addSearchContacts', [
            'key' => $this->key,
            'unionId' => $unionId,
            'userId' => $userId,
            'verifyText' => empty($verifyText) ? '通过手机号搜索添加' : ''
        ]);
        return $data;
    }

    /**
     * 获取企业信息
     * @param array $corpIdList
     * @return array
     */
    public function getCorpInfo(array $corpIdList): mixed
    {
        logger()->info("获取企业信息...".json_encode($corpIdList));
        $data = $this->post('/common/getCorpInfo', [
            'key' => $this->key,
            'corpIdList' => $corpIdList
        ]);
        return $data;
    }

    /**
     * 获取外部联系人列表
     * @param mixed $currentSeq 分页参数首次传0 之后传上一次查询返回的值;
     * @return array
     */
    public function getContactList(mixed $currentSeq = 0)
    {
        $data = $this->post('/contact/list', [
            'key' => $this->key,
            'currentSeq' => $currentSeq
        ]);
        return $data;
    }

    /**
     * 获取联系人详情
     * @param array $userIdList
     * @return array
     */
    public function getContactDetail(array $userIdList): mixed
    {
        $data = $this->post('/contact/detail', [
            'key' => $this->key,
            'userIdList' => $userIdList
        ]);
        return $data;
    }

    /**
     * 删除好友
     * @param mixed $userId
     * @return array
     */
    public function deleteFriend(mixed $userId): mixed
    {
        $data = $this->post('/friend/delFriend', [
            'key' => $this->key,
            'userId' => $userId
        ]);
        return $data;
    }

    /**
     * 获取会话列表
     * @param int $currentSeq
     * @return array
     */
    public function getSessionList(int $currentSeq = 0): mixed
    {
        $data = $this->post('/common/getSessionList', [
            'key' => $this->key,
            'currentSeq' => $currentSeq
        ]);
        return $data;
    }

    /**
     * 获取标签列表
     * @param int $labelType
     * @param int $currentSeq
     * @return array
     */
    public function getTagList(int $labelType, int $currentSeq = 0): mixed
    {
        $data = $this->post('/label/list', [
            'key' => $this->key,
            'labelType' => $labelType,
            'currentSeq' => $currentSeq
        ]);
        return $data;
    }

    /**
     * 标签增删改
     * @param int $opType
     * @param array $paramList
     * @return array
     */
    public function tagOp(int $opType,array $paramList): mixed
    {
        $data = $this->post('/label/op', [
            'key' => $this->key,
            'opType' => $opType,
            'paramList' => $paramList
        ]);
        return $data;
    }

    /**
     * @param int $opType 1=增加成员 2=删除成员
     * @param array $paramList
     * @return array
     */
    public function tagMemberOp(int $opType,array $paramList): mixed
    {
        $data = $this->post('/label/labelMemberOp', [
            'key' => $this->key,
            'opType' => $opType,
            'paramList' => $paramList
        ]);
        return $data;
    }


    /**
     * 获取群列表
     * @param int $nextStartIndex
     * @return array
     */
    public function getRoomList(int $nextStartIndex = 0): mixed
    {
        $data = $this->post('/room/list', [
            'key' => $this->key,
            'nextStartIndex' => $nextStartIndex
        ]);
        return $data;
    }

    /**
     * 获取群详情
     * @param array $roomIdList
     * @return array
     */
    public function getRoomDetail(array $roomIdList): mixed
    {
        return $this->retryableRequest(function () use ($roomIdList){
            return $this->post('/room/detail', [
                'key' => $this->key,
                'roomIdList' => $roomIdList
            ]);
        });
    }

    /**
     * 生成群聊二维码
     * @param mixed $roomId
     * @return array
     */
    public function generateRoomQRCode(mixed $roomId): mixed
    {
        $data = $this->post('/workbench/generateRoomQRCode', [
            'key' => $this->key,
            'roomId' => $roomId
        ]);
        return $data;
    }

    /**
     * 移除群成员
     * @param mixed $roomId
     * @param array $memberList
     * @return array
     */
    public function removeRoomMember(mixed $roomId,array $memberList): mixed
    {
        $data = $this->post('/room/removeRoomMember', [
            'key' => $this->key,
            'roomId' => $roomId,
            'memberList' => $memberList,
            'isOuterRoom' => 1
        ]);
        return $data;
    }

    /**
     * @param string $content
     * @param string $toId
     * @return array
     */
    public function sendTextMsg(string $content,string $toId): mixed
    {
        $data = $this->post('/message/sendText', [
            'key' => $this->key,
            'content' => $content,
            'toId' => $toId
        ]);
        return $data;
    }

    /**
     * 混合文本消息
     * @param array $content
     * @param string $toId
     * @return mixed
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function sendMixTxtMsg(array $content,string $toId): mixed
    {
        $data = $this->post('/message/sndMixTxtMsg', [
            'key' => $this->key,
            'content' => $content,
            'toId' => $toId
        ]);
        return $data;
    }

    /**
     * 发送图片消息
     * @param ImageMessageDTO $imageMessage
     * @return array
     */
    public function sendImageMsg(ImageMessageDTO $imageMessage): mixed
    {
        $data = $this->post('/message/sendImage', array_merge([
            'key' => $this->key
        ], $imageMessage->toArray()));
        return $data;
    }

    /**
     * 发送视频消息
     * @param VideoMessageDTO $videoMessage
     * @return array
     */
    public function sendVideoMsg(VideoMessageDTO $videoMessage): mixed
    {
        $data = $this->post('/message/sendVideo', array_merge([
            'key' => $this->key
        ], $videoMessage->toArray()));
        return $data;
    }

    /**
     * 发送文件消息
     * @param FileMessageDTO $fileMessageDTO
     * @return array
     */
    public function sendFileMsg(FileMessageDTO $fileMessageDTO): mixed
    {
        $data = $this->post('/message/sendFile', array_merge([
            'key' => $this->key
        ], $fileMessageDTO->toArray()));
        return $data;
    }

    /**
     * 发送链接消息
     * @param UrlMessageDTO $urlMessageDTO
     * @return array
     */
    public function sendUrlMsg(UrlMessageDTO $urlMessageDTO): mixed
    {
        $data = $this->post('/message/sendUrl', array_merge([
            'key' => $this->key
        ], $urlMessageDTO->toArray()));
        return $data;
    }

    /**
     * 发送视频号消息
     * @param VideoChannelMessageDTO $videoChannelMessageDTO
     * @return array
     */
    public function sendVideoChannelMsg(VideoChannelMessageDTO $videoChannelMessageDTO): mixed
    {
        $data = $this->post('/message/sendVideoChannel', array_merge([
            'key' => $this->key
        ], $videoChannelMessageDTO->toArray()));
        return $data;
    }

    /**
     * 发送小程序消息
     * @param MiniProgramMessageDTO $miniProgramMessageDTO
     * @return array
     */
    public function sendMiniProgram(MiniProgramMessageDTO $miniProgramMessageDTO): mixed
    {
        $data = $this->post('/message/sendMiniProgram', array_merge([
            'key' => $this->key
        ], $miniProgramMessageDTO->toArray()));
        return $data;
    }

    public function sendQuoteMsg(QuoteMsgDTO $quoteMsgDTO): mixed
    {
        $data = $this->post('/message/quoteMsg', array_merge([
            'key' => $this->key
        ], $quoteMsgDTO->toArray()));
        return $data;
    }

    /**
     * 发送名片消息
     * @param mixed $sharedId
     * @return mixed
     */
    public function sendBusinessCard(mixed $toId,mixed $sharedId): mixed
    {
        $data = $this->post('/message/sendCard', array_merge([
            'key' => $this->key
        ], [
            'toId' => $toId,
            'sharedId' => $sharedId
        ]));
        return $data;
    }

    public function sendEmojiMsg(EmojiMsgDTO $emojiMsgDTO): mixed
    {
        $data = $this->post('/message/sendGif', array_merge([
            'key' => $this->key
        ], $emojiMsgDTO->toArray()));
        return $data;
    }

    /**
     * 撤回消息
     * @param mixed $chatId
     * @param int $msgServerId
     * @return array
     */
    public function recallMessage(mixed $chatId,int $msgServerId): bool|array
    {
        $data = $this->post('/message/recallMessage', [
            'key' => $this->key,
            'chatId' => $chatId,
            'msgServerId' => $msgServerId
        ]);
        return $data;
    }

    /**
     * 数据同步
     * @param int $businessId 1. 外部联系人信息变动的数据 2. 好友申请的数据 13. 内部联系人信息变动的数据
     * @param int $msgSeq
     * @return array
     */
    public function dataSync(int $businessId,int $msgSeq = 0): mixed
    {
        $data = $this->post('/common/dataSync', [
            'key' => $this->key,
            'businessId' => $businessId,
            'msgSeq' => $msgSeq
        ]);
        return $data;
    }

    public function histMsgSync(int $msgSeq = 0,?int $limit = null)
    {
        $data = $this->post('/message/histMsgSync', [
            'key' => $this->key,
            'msgSeq' => $msgSeq,
            'limit' => $limit
        ]);
        return $data;
    }

    /**
     * 发布朋友圈文件上传
     * @param string $fileUrl
     * @return array
     */
    public function friendCircleUpload(string $fileUrl): mixed
    {
        $data = $this->post('/friendCircle/uploadFile', [
            'key' => $this->key,
            'fileUrl' => $fileUrl,
            'fileType' => 35
        ]);
        return $data;
    }

    /**
     * 发布朋友圈
     * @param string $content
     * @param array $visibleUserIdList
     * @param array $linkInfo
     * @param array $mediaList
     * @return array
     */
    public function sendFriendCircle(string $content,array $visibleUserIdList = [],array $linkInfo =[],array $mediaList = []): mixed
    {
        $postData = [
            'key' => $this->key,
            'content' => $content,
        ];

        !empty($visibleUserIdList) && $postData['visibleUserIdList'] = $visibleUserIdList;
        !empty($linkInfo) && $postData['linkInfo'] = $linkInfo;
        !empty($mediaList) && $postData['mediaList'] = $mediaList;

        $data = $this->post('/friendCircle/postFriendCircle', $postData);
        return $data;
    }

    /**
     * 获取朋友圈详情
     * @param array $snsIdList
     * @return array
     */
    public function getFriendCircleDetail(array $snsIdList): mixed
    {
        $postData = [
            'key' => $this->key,
            'snsIdList' => $snsIdList,
        ];
        $data = $this->post('/friendCircle/detail', $postData);
        return $data;
    }

    /**
     * 评论朋友圈
     * @param mixed $snsId
     * @param string $content
     * @param mixed $refCommentId 评论id如果是直接评论自己填0即可，可以通过【获取朋友圈详情接口】得到所有的评论ID
     *
     * @return array
     */
    public function commentFriendCircle(mixed $snsId,string $content,mixed $refCommentId = 0): mixed
    {
        $postData = [
            'key' => $this->key,
            'snsId' => $snsId,
            'content' => $content,
            'refCommentId' => $refCommentId
        ];
        $data = $this->post('/friendCircle/comment', $postData);
        return $data;
    }

    /**
     * 删除朋友圈
     * @param mixed $snsId
     * @return array
     */
    public function deleteFriendCircle(mixed $snsId): mixed
    {
        $postData = [
            'key' => $this->key,
            'snsId' => $snsId,
        ];
        $data = $this->post('/friendCircle/delete', $postData);
        return $data;
    }

    /**
     * 联系人ID转openid
     * @param array $userIdList
     * @return array
     */
    public function useridToOpenuserid(array $userIdList): mixed
    {
        $postData = [
            'key' => $this->key,
            'userIdList' => $userIdList,
        ];
        $data = $this->post('/common/useridToOpenuserid', $postData);
        return !empty($data['open_user_list'])?$data['open_user_list']:[];
    }

    /**
     * 群ID转OpenID
     * @param string roomId
     * @return array
     */
    public function roomidToOpenroomid(string $roomId): mixed
    {
        $postData = [
            'key' => $this->key,
            'roomId' => $roomId,
        ];
        $data = $this->post('/common/roomidToOpenroomid', $postData);
        return $data;
    }


    /**
     * 文件上传
     * @param string $fileUrl
     * @param int $fileType
     * @return array
     */
    public function fileUpload(string $fileUrl,int $fileType): mixed
    {
        $postData = [
            'key' => $this->key,
            'fileUrl' => $fileUrl,
            'fileType' => $fileType
        ];
        $data = $this->post('/file/upload', $postData);
        return $data;
    }

    public function cdnToUrl(string $fileAesKey,string $fileId,string $fileMd5)
    {
        $postData = [
            'key' => $this->key,
            'fileAesKey' => $fileAesKey,
            'fileId' => $fileId,
            'fileMd5' => $fileMd5
        ];
        $data = $this->post('/file/cdnToUrl', $postData);
        return $data;
    }

    /**
     * 下载企微文件
     * @param string $fileAesKey
     * @param string $fileId
     * @param int $fileSize
     * @param string $fileName
     * @param int $fileType
     * @return array|false|mixed
     */
    public function downloadWeComDdn(string $fileAesKey,string $fileId,int $fileSize,string $fileName,int $fileType)
    {
        $postData = [
            'key' => $this->key,
            'fileAesKey' => $fileAesKey,
            'fileId' => $fileId,
            'fileSize' => $fileSize,
            'fileName' => $fileName,
            'fileType' => $fileType
        ];
        $data = $this->post('/file/downloadWeComDdn', $postData);
        return $data;
    }

    /**
     * 下载个微文件
     * @param string $fileAesKey
     * @param string $fileAuthKey
     * @param int $fileSize
     * @param string $fileUrl
     * @param string $fileName
     * @param int $fileType
     * @return mixed
     */
    public function downloadWeChatDdn(string $fileAesKey,string $fileAuthKey,int $fileSize,string $fileUrl,string $fileName,int $fileType): mixed
    {
        $postData = [
            'key' => $this->key,
            'fileAesKey' => $fileAesKey,
            'fileAuthKey' => $fileAuthKey,
            'fileSize' => $fileSize,
            'fileUrl' => $fileUrl,
            'fileName' => $fileName,
            'fileType' => $fileType
        ];
        $data = $this->post('/file/downloadWeChatDdn', $postData);
        return $data;
    }

    /**
     * 邀请好友进群
     * @param string $roomId
     * @param array $memberList
     * @return array
     */
    public function inviteFriendToRoom(string $roomId,array $memberList): mixed
    {
        $data = $this->post('/room/inviteFriendToRoom', [
            'key' => $this->key,
            'roomId' => $roomId,
            'memberList'=>$memberList,
            'isOuterRoom' => 1
        ]);
        return $data;
    }


    /**
     * 创建群聊
     * @param array $memberList
     * @return array
     */
    public function createRoom(array $memberList): mixed
    {
        $data = $this->post('/room/create', [
            'key' => $this->key,
            'memberList'=>$memberList,
            'isOuterRoom' => 1
        ]);
        return $data;
    }

    /**
     * 转让群主
     * @param mixed $roomId
     * @param mixed $newOwnerId
     * @return array
     */
    public function transferRoomOwner(mixed $roomId,mixed $newOwnerId): mixed
    {
        $data = $this->post('/room/transferRoomOwner', [
            'key' => $this->key,
            'roomId'=> $roomId,
            'newOwnerId' => $newOwnerId
        ]);
        return $data;
    }

    /**
     * 设置管理员
     * @param mixed $roomId
     * @param array $memberList
     * @param bool $isSet true设置管理员，false取消管理员
     * @return array
     */
    public function setRoomAdmin(mixed $roomId,array $memberList,bool $isSet = true): mixed
    {
        $data = $this->post('/room/setRmvGrpAdmin', [
            'key' => $this->key,
            'roomId'=> $roomId,
            'memberList' => $memberList,
            'isSet' => $isSet
        ]);
        return $data;
    }

    /**
     * 修改群名称
     * @param mixed $roomId
     * @param string $roomName
     * @return array
     */
    public function editRoomName(mixed $roomId,string $roomName): mixed
    {
        $data = $this->post('/room/editRoomName', [
            'key' => $this->key,
            'roomId'=>$roomId,
            'name' => $roomName
        ]);
        return $data;
    }

    /**
     * 退出群聊
     * @param mixed $roomWxid
     * @return array
     */
    public function outRoom(mixed $roomWxid): mixed
    {
        $data = $this->post('/room/exitRoom', [
            'key' => $this->key,
            'roomId'=>$roomWxid,
        ]);
        return $data;
    }

    /**
     * 发送群公告
     * @param mixed $roomId
     * @param mixed $newOwnerId
     * @return array
     */
    public function postGrpAnn(mixed $roomId,string $notice): mixed
    {
        $data = $this->post('/room/postGrpAnn', [
            'key' => $this->key,
            'roomId'=> $roomId,
            'notice' => $notice
        ]);
        return $data;
    }

    /**
     * 获取个人二维码
     * @return array|false|mixed
     */
    public function getPersonalQRCode(): mixed
    {
        $data = $this->post('/workbench/personalQRCode', [
            'key' => $this->key,
        ]);
        return $data;
    }

    public function agreeFriendApply(mixed $userId,mixed $corpId): mixed
    {
        $data = $this->post('/friend/agreeFriendApply', [
            'key' => $this->key,
            'userId' => $userId,
            'corpId' => '',
        ]);
        return $data;
    }

    /**
     * @param $uri
     * @param $data
     * @return array|false|mixed
     */
    private function post($uri, $data): mixed
    {
        try{
            $response = $this->client->post($uri, [
                'json' => $data
            ]);
            $response = $this->packer->unpack((string)$response->getBody());
            if($uri == '/login/verifyLogin'){
                stdout_log()->info("验证结果".json_encode($response,JSON_UNESCAPED_UNICODE));
            }

            if ($response['code'] != 200) {
                if($this->throw){
                    throw new NormalStatusException($response['msg']);
                }else{
                    $this->errorMsg = $response['msg'];
                    logger()->info("【{$uri}】机器人接口请求返回失败：".json_encode($response));
                    return false;
                }
            }
            return $response['data'] ?? [];
        }catch(\Throwable $e){
            if($uri == '/login/verifyLogin'){
                stdout_log()->info("验证结果".$e->getMessage());
            }
            logger()->info("【{$uri}】请求失败：".$e->getMessage());
            return false;
        }
    }

    /**
     * 通用重试请求方法
     *
     * @param callable $requestCallback 请求回调函数，返回非false表示成功
     * @param int $maxAttempts 最大尝试次数（包含首次请求）
     * @param float $retryDelay 重试延迟时间（秒）
     * @return mixed 成功返回请求结果，失败返回false
     */
    private function retryableRequest(callable $requestCallback, int $maxAttempts = 3, float $retryDelay = 1): mixed
    {
        for ($attempt = 1; $attempt <= $maxAttempts; $attempt++) {
            $result = $requestCallback();

            if ($result !== false) {
                return $result;
            }

            // 最后一次失败不需要再等待
            if ($attempt < $maxAttempts) {
                Coroutine::sleep($retryDelay);
            }
        }

        return false;
    }

    /**
     * 获取异常信息
     * @return mixed
     */
    public function getErrorMsg(): mixed
    {
        return $this->errorMsg;
    }

}